package com.millstein.tsinglog.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.millstein.tsinglog.commons.constant.SystemConstant;
import com.millstein.tsinglog.commons.enums.ResultCode;
import com.millstein.tsinglog.exception.TsinglogException;
import com.millstein.tsinglog.commons.service.BaseService;
import com.millstein.tsinglog.mapper.biz.ArticleContentMapper;
import com.millstein.tsinglog.mapper.biz.ArticleMapper;
import com.millstein.tsinglog.mapper.biz.CarouselImageMapper;
import com.millstein.tsinglog.mapper.biz.CarouselMapper;
import com.millstein.tsinglog.model.dto.carousel.CarouselImageSaveDTO;
import com.millstein.tsinglog.model.dto.carousel.CarouselSaveDTO;
import com.millstein.tsinglog.model.pojo.Article;
import com.millstein.tsinglog.model.pojo.ArticleContent;
import com.millstein.tsinglog.model.pojo.CarouselImage;
import com.millstein.tsinglog.model.vo.result.PageResult;
import com.millstein.tsinglog.service.CarouselService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class CarouselServiceImpl extends BaseService implements CarouselService {

    @Autowired
    private CarouselMapper carouselMapper;

    @Autowired
    private CarouselImageMapper carouselImageMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleContentMapper articleContentMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public PageResult<CarouselImage> getImagesByPage(Integer currentPage, Integer pageSize, String keyword) {

        // 1.处理参数
        if (currentPage == null) {
            currentPage = SystemConstant.DEFAULT_CURRENT_PAGE;
        }
        if (pageSize == null) {
            pageSize = SystemConstant.DEFAULT_PAGE_SIZE;
        }

        // 2.条件查询
        Example example = new Example(CarouselImage.class);
        Example.Criteria criteria = example.createCriteria();

        if (StringUtils.isNotBlank(keyword)) {
            criteria.andLike("articleTitle", "%" + keyword + "%");
        }

        // 3.排除状态为删除的记录
        criteria.andEqualTo("status", SystemConstant.STATUS_ENTITY_NORMAL);

        // 4.排序
        example.setOrderByClause("usable desc, update_time desc");

        // 5.开始查询
        PageHelper.startPage(currentPage, pageSize);
        List<CarouselImage> list = carouselImageMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }

        // 6.完善articleTitle和articleLink和picUrl的信息
        for (CarouselImage image : list) {
            this.completeFieldsForCarouselImageForManager(image);
        }

        PageInfo pageInfo = new PageInfo(list);

        return new PageResult<CarouselImage>(pageInfo.getTotal(), pageInfo.getPages(), list);
    }

    @Override
    public void changeUsable(Long id, Short usable) {

        if (id == null || usable == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        CarouselImage image = carouselImageMapper.selectCarouselImageByPrimaryKeyForServer(id);
        if (image == null) {
            throw new TsinglogException(ResultCode.HANDLE_DATA_NOT_EXISTED);
        }

        image.setUsable(usable);
        image.setUpdateTime(getCurrentDateStr());
        int result = carouselImageMapper.updateByPrimaryKey(image);
        if (result != 1) {
            throw new TsinglogException(ResultCode.UPDATE_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST);
    }

    @Override
    @Transactional
    public void saveConfig(CarouselSaveDTO carouselSaveDTO) {

        Long interval = carouselSaveDTO.getInterval();
        Integer maxNum = carouselSaveDTO.getMaxNum();

        // 校验maxNum的值是否是3,5,7,9中的任意一个
        String allowedNum = SystemConstant.ALLOWED_SHOW_IMAGE_NUM_FOR_PORTAL;
        String[] split = allowedNum.split(",");
        List<Integer> collect = Arrays.asList(split).stream().map(item -> Integer.parseInt(item)).collect(Collectors.toList());
        if (collect.indexOf(maxNum) == -1) {
            throw new TsinglogException(ResultCode.PARAM_IS_INVALID);
        }

        int result = carouselMapper.updateConfigValueByConfigKey(SystemConstant.INTERVAL_KEY, interval, getCurrentDateStr());
        result += carouselMapper.updateConfigValueByConfigKey(SystemConstant.MAX_NUM_KEY, maxNum, getCurrentDateStr());

        if (result != 2) {
            throw new TsinglogException(ResultCode.UPDATE_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_PREFIX_FOR_CAROUSEL + SystemConstant.INTERVAL_KEY);
        redisTemplate.delete(SystemConstant.REDIS_PREFIX_FOR_CAROUSEL + SystemConstant.MAX_NUM_KEY);

    }

    @Override
    public Object getConfigByKey(String key) {

        if (StringUtils.isBlank(key)) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        Object result;
        String redisKey = SystemConstant.REDIS_PREFIX_FOR_CAROUSEL + key;

        ValueOperations operations = redisTemplate.opsForValue();

        if (redisTemplate.hasKey(redisKey)) {
            result = operations.get(redisKey);
        } else {
            result = carouselMapper.getConfigByKey(key);
            if (result == null) {
                throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
            }
            operations.set(redisKey, result);
        }

        return result;
    }

    @Override
    public void insertCarouselImage(CarouselImageSaveDTO carouselImageSaveDTO) {

        // 1.数据校验
        this.checkDTOByType(carouselImageSaveDTO);

        // 2.保存
        CarouselImage image = new CarouselImage();

        this.assignImageByDTO(image, carouselImageSaveDTO, true);
        int result = carouselImageMapper.insert(image);
        if (result != 1) {
            throw new TsinglogException(ResultCode.INSERT_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST);
    }

    @Override
    public void updateCarouselImage(CarouselImageSaveDTO carouselImageSaveDTO) {

        // 1.数据校验
        Long id = carouselImageSaveDTO.getId();
        if (id == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        this.checkDTOByType(carouselImageSaveDTO);

        CarouselImage dbImage = carouselImageMapper.selectCarouselImageByPrimaryKeyForServer(id);
        if (dbImage == null) {
            throw new TsinglogException(ResultCode.HANDLE_DATA_NOT_EXISTED);
        }

        // 2.保存
        this.assignImageByDTO(dbImage, carouselImageSaveDTO, false);

        int result = carouselImageMapper.updateByPrimaryKey(dbImage);
        if (result != 1) {
            throw new TsinglogException(ResultCode.UPDATE_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST);
    }

    /**
     * 用carouselImageSaveDTO的内容为carouselImage对象赋值
     *
     * @param image
     * @param carouselImageSaveDTO
     * @param insertFlag           是否是新增操作，true为新增操作，false为修改操作
     */
    private void assignImageByDTO(CarouselImage image, CarouselImageSaveDTO carouselImageSaveDTO, Boolean insertFlag) {
        image.setType(carouselImageSaveDTO.getImageType());
        image.setAid(carouselImageSaveDTO.getAid());
        image.setArticleTitle(carouselImageSaveDTO.getOuterArticleTitle());
        image.setArticleLink(carouselImageSaveDTO.getOuterArticleUrl());
        image.setPicUrl(carouselImageSaveDTO.getImagePreviewUrl());
        image.setSort(carouselImageSaveDTO.getSort());
        image.setUsable(carouselImageSaveDTO.getUsable());
        image.setExpireTime(carouselImageSaveDTO.getExpireTime());
        image.setUpdateTime(getCurrentDateStr());
        if (insertFlag) {
            image.setStatus(SystemConstant.STATUS_ENTITY_NORMAL);
            image.setCreateTime(getCurrentDateStr());
        }

    }

    @Override
    @Transactional
    public void deleteByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        for (Long id : ids) {
            CarouselImage dbImage = carouselImageMapper.selectCarouselImageByPrimaryKeyForServer(id);
            if (dbImage == null) {
                throw new TsinglogException(ResultCode.HANDLE_DATA_NOT_EXISTED);
            }

            dbImage.setStatus(SystemConstant.STATUS_ENTITY_DELETE);
            dbImage.setUpdateTime(getCurrentDateStr());

            int result = carouselImageMapper.updateByPrimaryKey(dbImage);
            if (result != 1) {
                throw new TsinglogException(ResultCode.DELETE_FAILURE);
            }
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST);
    }

    @Override
    public List<CarouselImage> getCarouselImageListForPortal() {

        ValueOperations operations = redisTemplate.opsForValue();

        if (redisTemplate.hasKey(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST)) {
            return (List<CarouselImage>) operations.get(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST);
        }

        // 1.获取需要显示轮播图的数量
        int num = Integer.parseInt((String) this.getConfigByKey("showNum"));
        // 2.获取对应数据的轮播图信息
        Example example = new Example(CarouselImage.class);
        Example.Criteria criteria = example.createCriteria();

        criteria.andEqualTo("usable", SystemConstant.USABLE_ENTITY_ON);
        criteria.andEqualTo("status", SystemConstant.STATUS_ENTITY_NORMAL);

        example.setOrderByClause("sort asc, create_time desc");

        PageHelper.startPage(SystemConstant.DEFAULT_CURRENT_PAGE, num);
        List<CarouselImage> list = carouselImageMapper.selectByExample(example);

        List<CarouselImage> returnList = new ArrayList<>();
        // 3.给本地文章对应的轮播图填充值
        if (!CollectionUtils.isEmpty(list)) {
            for (CarouselImage image : list) {
                this.completeFieldsForCarouselImageForPortal(image);
                returnList.add(image);
            }
        }

        operations.set(SystemConstant.REDIS_KEY_FOR_CAROUSEL_IMAGE_LIST, returnList);

        return returnList;
    }

    @Override
    public CarouselImage getCarouselImageById(Long id) {
        if (id == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        CarouselImage dbImage = carouselImageMapper.selectCarouselImageByPrimaryKeyForServer(id);
        if (dbImage == null) {
            throw new TsinglogException(ResultCode.HANDLE_DATA_NOT_EXISTED);
        }

        this.completeFieldsForCarouselImageForManager(dbImage);
        return dbImage;
    }


    /**
     * 为后台完善carouselImage的articleTitle、articleLink和picUrl的信息
     *
     * @param image 待完善字段的carouselImage实体
     */
    private void completeFieldsForCarouselImageForManager(CarouselImage image) {
        // 本地文章需要完善
        if (image.getType() == SystemConstant.LOCAL_ARTICLE) {
            // 1.完善articleLink
            image.setArticleLink(SystemConstant.PATH_PORTAL_PLACEHOLDER + "/article/" + image.getAid());
            // 2.完善articleTitle和picUrl
            this.completeTitleAndUrlForLocalArticle(image, true);
        } else {
            // 非本地文章在为前台提供数据的时候需要完善picUrl字段
            image.setPicUrl(SystemConstant.IMAGE_PREFIX + image.getPicUrl());
        }
    }

    /**
     * 为前台完善carouselImage的articleTitle、articleLink和picUrl的信息
     *
     * @param image 待完善字段的carouselImage实体
     */
    private void completeFieldsForCarouselImageForPortal(CarouselImage image) {
        if (image.getType() == SystemConstant.LOCAL_ARTICLE) {
            // 本地文章完善articleTitle、articleLink和picUrl这三个字段
            // 1.完善articleLink
            image.setArticleLink(SystemConstant.PORTAL_ARTICLE_URL + image.getAid());
            // 2.完善articleTitle和picUrl
            this.completeTitleAndUrlForLocalArticle(image, false);
        } else {
            // 非本地文章在为前台提供数据的时候需要完善picUrl字段
            image.setPicUrl(SystemConstant.IMAGE_PREFIX + image.getPicUrl());
        }
    }

    /**
     * 为本地文章完善articleTitle和picUrl字段的信息
     * @param image
     * @param isForServer 是否为后台提供数据，true为是，false为前台提供数据
     */
    private void completeTitleAndUrlForLocalArticle(CarouselImage image, Boolean isForServer) {
        // 1.完善articleTitle
        if (image.getAid() == null) {
            throw new TsinglogException(ResultCode.PARAM_NOT_COMPLETE);
        }
        Article dbArticle;
        if (isForServer) {
            dbArticle = articleMapper.selectArticleByPrimaryKeyForServer(image.getAid());
        } else {
            dbArticle = articleMapper.selectArticleByPrimaryKeyForWeb(image.getAid());
        }

        if (dbArticle == null) {
            throw new TsinglogException(ResultCode.HANDLE_DATA_NOT_EXISTED);
        }
        image.setArticleTitle(dbArticle.getTitle());
        // 2.完善picUrl
        ArticleContent entity = new ArticleContent();
        entity.setArticleId(image.getAid());
        ArticleContent dbContent = articleContentMapper.selectOne(entity);
        if (dbContent == null) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }
        image.setPicUrl(SystemConstant.IMAGE_PREFIX + dbContent.getCoverImage());
    }

    /**
     * 根据type检查carouselImageSaveDTO中的值是否合法
     *
     * @param carouselImageSaveDTO
     */
    private void checkDTOByType(CarouselImageSaveDTO carouselImageSaveDTO) {
        Short type = carouselImageSaveDTO.getImageType();

        if (type == SystemConstant.LOCAL_ARTICLE) {
            if (carouselImageSaveDTO.getAid() == null) {
                throw new TsinglogException(ResultCode.PARAM_NOT_COMPLETE);
            }
        } else if (type == SystemConstant.OUTER_ARTICLE) {
            if (StringUtils.isBlank(carouselImageSaveDTO.getOuterArticleTitle())) {
                throw new TsinglogException(ResultCode.PARAM_NOT_COMPLETE);
            }
            if (StringUtils.isBlank(carouselImageSaveDTO.getOuterArticleUrl())) {
                throw new TsinglogException(ResultCode.PARAM_NOT_COMPLETE);
            }
            if (StringUtils.isBlank(carouselImageSaveDTO.getImagePreviewUrl())) {
                throw new TsinglogException(ResultCode.PARAM_NOT_COMPLETE);
            }
        } else {
            throw new TsinglogException(ResultCode.PARAM_IS_INVALID);
        }
    }
}
